package logica;

import dados.Aluno;
import dados.ArquivoFonte;
import dados.BancoQuestoes;
import dados.Estado;
import dados.ListaQuestoes;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;

import dados.PastaCorrecao;
import dados.Questao;

/**
 * Esta classe cont�m m�todos que manipulam arquivos de diversas formas.
 */
public abstract class Arquivos {
	
    /** 
     * Retorna o texto que est� contido em um determinado arquivo.
     * na forma de String. 
     * @param arquivo O Nome do Arquivo.
     * @return O texto do arquivo em forma de String.
     */
    public static String getTextoArquivo(File arquivo) throws IOException {
        if (arquivo.length() < Constantes.TAM_MAX_ARQ) {
            StringBuffer buffer = new StringBuffer();
            BufferedReader in = new BufferedReader (new InputStreamReader (
                                    new FileInputStream (arquivo), "UTF-8"));
            String line;
            while((line = in.readLine()) != null) {
                buffer.append(line + "\n");
            }
            in.close();
            return buffer.toString();
        }
        return "";
    }
        
    public static String[] getEntrada(File arquivo) throws IOException {
    	BufferedReader br = null;
		String[] entradas = new String[100];
		String linha;
		int i = 0;
		
		try {
			br = new BufferedReader(new FileReader(arquivo));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		try {
			while( (linha = br.readLine()) != null ){
				if(linha.contains("#---#")){
					break;
				}
				entradas[i++] = linha;		
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		String[] retorna = new String[i];
		for(int j = 0; j < i; j++)
			retorna[j] = entradas[j];
		return retorna;
    }
    
    public static String[] getColunas(File arquivo) throws IOException {
    	BufferedReader br = null;
		String linha = null;
		
		try {
			br = new BufferedReader(new FileReader(arquivo));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		try {
			while( (linha = br.readLine()) != null ){
				if(linha.contains("#---#")){
					break;
				}		
			}
			linha = br.readLine();
		} catch (IOException e) {
			e.printStackTrace();
		}
		if(linha != null){
			String[] retorna = linha.split("#");
			return retorna;
		}
		return null;
    }
    
    public static String[] getGabaritos(File arquivo, int ncol) throws IOException {
    	BufferedReader br = null;
    	String[] aux = new String[ncol];
		String[] gabaritos = new String[100];
		String linha;
		int i = 0;
		
		try {
			br = new BufferedReader(new FileReader(arquivo));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
		try {
			while( (linha = br.readLine()) != null ){
				if(linha.contains("#---#")){
					break;
				}		
			}
			linha = br.readLine();
			while( (linha = br.readLine()) != null ){
				aux = linha.split("#");
				if(aux.length == ncol){
					for(int k = 0; k < ncol; k++){
						gabaritos[i++] = aux[k];
					}
				}else{
					System.out.println("O numero de colunas do gabarito difere do definido");
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		String[] retorna = new String[i];
		for(int j = 0; j < i; j++)
			retorna[j] = gabaritos[j];
		return retorna;
    }
    
    /**
     * 
     */
    public static void retirarStrings(File arquivo){
    	String str = null;
    	String str2;
    	try {
			str = Arquivos.getTextoArquivo(arquivo);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		str2 = retirar(str);
			
    	FileWriter writer = null;
    	try {
    		writer = new FileWriter(arquivo,false);
    	} catch (IOException e) {
    		e.printStackTrace();
    	}
    	PrintWriter saida = new PrintWriter(writer,true);
    	
    	saida.println(str2);
    	saida.close();
    	
    	try {
    		writer.close();
    	} catch (IOException e) {
    		e.printStackTrace();
    	}
    }
    
    public static String retirar(String str){
    	String[] linhas = null;
    	int i,j,k,l,m,n,o,p,q,r,z;
    	i = j = p = l = n = q = r = -1;
    	k = m = o = z = 0; 
    	
    	int flag = 0;
    	String aux = null;
    	String aux2 = null;
    	String aspas = "";    		  
    	
    	linhas = str.split("\n");
    	
    	while(k < linhas.length){
    		linhas[k] = linhas[k].toLowerCase();
    		i = linhas[k].indexOf("writeln");
    		j = linhas[k].indexOf("readln");
    		l = linhas[k].indexOf("read");
    		n = linhas[k].indexOf("write");
    		q = linhas[k].indexOf("var");
    		r = linhas[k].indexOf("text");
    		
    		if(!(q >= 0 && r >= 0)){
	    		if(i >= 0 || n >= 0){
	    			if(i >=0)
	    				m = i;
	    			else
	    				m = n;
	    			
	    			while(m < linhas[k].length()){
	    				if(linhas[k].charAt(m) == ' '){
	    					aux = linhas[k].substring(0, m);
	    					aux2 = linhas[k].substring(m+1, linhas[k].length());
	    					aux = aux + aux2;
	    					linhas[k] = aux;
	    					m--;
	    					//System.exit(0);
	    				}else{
							aspas = aux = aux2 = "";
							if(linhas[k].charAt(m) == '\''){
								aux = linhas[k].substring(0, m+1);
								m++;
								o = m;
								while(o < linhas[k].length()){
									if(linhas[k].charAt(o) == '\''){
										break;
									}
									aspas = aspas + linhas[k].charAt(o);
									o++;
								}
								z = flag = 0;
								while(z < aspas.length()){
									if(aspas.charAt(z) != ' '){
										flag = 1;
										break;
									}
									z++;
									m++;
								}   					
								aux2 = linhas[k].substring(o, linhas[k].length());
								
								if(flag == 0){
									aux = aux + aspas;
									aux = aux + aux2;
								}else{
									aux = aux + aux2;
								}
								linhas[k] = aux;
							}
	    				}
	    				m++;
	    			}
	    			m = 0;
	    		}
	    		
	    		if(j >= 0 || l >= 0){
	    			if(j >= 0)
	    				m = j;
	    			else
	    				m = l;
	    				
	    			while(m < linhas[k].length()){
	    				aspas = aux = aux2 = "";
	    				if(linhas[k].charAt(m) == '\''){
	    					aux = linhas[k].substring(0, m+1);
	    					m++;
	    					o = m;
	    					while(o < linhas[k].length()){
	    						if(linhas[k].charAt(o) == '\''){
	    							break;
	    						}
	    						aspas = aspas + linhas[k].charAt(o);
	    						o++;
	    					} 					
	    					aux2 = linhas[k].substring(o, linhas[k].length());
	    					
	    					aux = aux + aux2;
	    					linhas[k] = aux;
	    				}
	    				m++;
	    			}
	    			m = 0;
				}
    		}
    		k++;
    		i = j = l = m = -1;
    	}
    	k = 0;
    	String linhaFinal = "";
    	
    	while(k < linhas.length){
    		p = linhas[k].indexOf("writeln('')");  		
    		if(p < 0){
    			p = linhas[k].indexOf("readln('')");
    			if(p < 0){
    				p = linhas[k].indexOf("write('')");
    				if(p < 0){
    					p = linhas[k].indexOf("read('')");
    					if(p < 0){
    						linhaFinal = linhaFinal + linhas[k] + "\n";
    					}
    				}
    			}
    		}
    		k++;
    		p = -1;
    	}    	
    	return linhaFinal;
    }
    
    /** 
     * Grava os dados que s�o passados dentro do arquivo e o fecha.
     * @param arquivo O caminho completo do arquivo no qual ser� gravado os dados.
     * @param texto O texto que ser� gravado no arquivo.
     */
    public static void salvarArquivo(File arquivo, String texto) throws IOException {
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
                        new FileOutputStream(arquivo), "UTF-8"));
        out.write(texto);
        out.close();
    }
    
    /**
     * Copia um arquivo para determinada quest�o dos alunos.
     * @param arquivo O arquivo que ser� copiado.
     * @param indiceQuestao O �ndice da quest�o para onde o arquivo ser� copiado.
     */
    public static void copiarArquivo(File arquivo, int indiceQuestao) throws IOException {
        Aluno[] todosAlunos = PastaCorrecao.getInstancia().getAlunos();
        for (Aluno aluno : todosAlunos) {
            ArquivoFonte[] fontes = aluno.getFontes();
            if ((fontes.length > indiceQuestao) && (fontes[indiceQuestao] != null)) {
                String diretorio = fontes[indiceQuestao].getArquivo().getParentFile().getAbsolutePath();
                File novoArquivo = new File(diretorio + "/" + arquivo.getName());
                InputStream in = new FileInputStream(arquivo);
                OutputStream out = new FileOutputStream(novoArquivo);

                // Transfere os bytes de um arquivo para o outro.
                byte[] buf = new byte[1024];
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }
                in.close();
                out.close();
            }
        }
    }

    /** 
     * Deleta um determinado arquivo.
     * @param arquivo O arquivo que ser� deletado.
     */
    public static void deletarArquivo(File arquivo) throws IOException {
        if (!arquivo.delete()) {
            throw new IOException();
        }
    }
    
    /**
     * Deleta um determinado dir�torio e todos os arquivos e subdiret�rios contidos nele.
     * @param diretorio O diret�rio que ser� deletado.
     * @return Um valor true se foi bem sucedido e falso caso contr�rio.
     */
    public static boolean deletarDiretorio(File diretorio) {
        // Para ver se o diret�rio � atualmente um link simb�lico para um diret�rio,
        // n�s precisamos pegar o caminho Can�nico - isto �, n�s seguimos o link para
        // o arquivo que ele est� atualmente linkado.
        File candir;
        try {
            candir = diretorio.getCanonicalFile();
        } catch (IOException e) {
            return false;
        }
  
        // Um link simb�lico tem um caminho can�nico diferente do que o seu
        // caminho atual, a menos que seja um link para si mesmo.
        if (!candir.equals(diretorio.getAbsoluteFile())) {
            // Este arquivo � um link simb�lico, e n�o h� nenhuma raz�o para
            // segu�-lo, porque poder�amos apagar algo que n�o deveria ser apagado.
            return false;
        }
  
        // Agora temos de passar por todos os arquivos e subdiret�rios no
        // diret�rio e elimin�-los um por um.
        File[] files = candir.listFiles();
        if (files != null) {
            for (int i = 0; i < files.length; i++) {
                File file = files[i];
  
                	
                // No caso deste diret�rio ser realmente uma liga��o simb�lica,
                // ou ele est� vazio, queremos tentar apagar o link antes de 
                // tentarmos qualquer coisa.
                boolean deleted = file.delete();
                if (!deleted) {
                    // Deletar o arquivo falhou, talvez seja um diret�rio n�o vazio.
                    if (file.isDirectory()) {
                        deletarDiretorio(file);
                    }
  
                   // Caso contr�rio, n�o h� nada mais que possamos fazer.
                }
            }
        }
  
        // Agora que tentamos limpar o diret�rio de fora, podemos tentar apag�-lo
        // novamente.
        return diretorio.delete();  
    }
    
    /**
     * Salva os dados armazenados na vari�vel de classe PastaCorrecao em um arquivo
     * que ser� utilizado para a importa��o posteriormente.
     */
    public static void serializarDados() {
       File arqCorrecao = new File(PastaCorrecao.getInstancia().getDiretorio().getAbsolutePath() + 
               "/" + Constantes.NARQ_COR);
       File arqListaQuestoes = new File(PastaCorrecao.getInstancia().getDiretorio().getAbsolutePath() + 
               "/" + Constantes.NARQ_LIS);
       File arqBancoQuestoes = new File(PastaCorrecao.getInstancia().getDiretorio().getAbsolutePath() + 
               "/" + Constantes.NARQ_BAN);
       FileOutputStream fosCorrecao, fosListaQuestoes, fosBancoQuestoes;
       ObjectOutputStream oosCorrecao, oosListaQuestoes, oosBancoQuestoes;
       
       try {
          fosCorrecao = new FileOutputStream(arqCorrecao);
          oosCorrecao = new ObjectOutputStream(fosCorrecao);
          fosListaQuestoes = new FileOutputStream(arqListaQuestoes);
          oosListaQuestoes = new ObjectOutputStream(fosListaQuestoes);
          fosBancoQuestoes = new FileOutputStream(arqBancoQuestoes);
          oosBancoQuestoes = new ObjectOutputStream(fosBancoQuestoes);
          
          oosCorrecao.writeObject((PastaCorrecao) PastaCorrecao.getInstancia());
          oosCorrecao.close();
          
          oosListaQuestoes.writeObject((ListaQuestoes) ListaQuestoes.getInstancia());
          oosListaQuestoes.close();
          
          oosBancoQuestoes.writeObject((BancoQuestoes) BancoQuestoes.getInstancia());
          oosBancoQuestoes.writeObject((Estado) Estado.getInstancia());
          oosBancoQuestoes.writeObject((int)BancoQuestoes.getEscolha());
          oosBancoQuestoes.writeObject((int)BancoQuestoes.getSimulado());
          oosBancoQuestoes.close();
          
       } catch (IOException e) {
          e.printStackTrace();
       }
    }
    
    public static void serializarDados(String nArq_Ban) {
       File arqCorrecao = new File(PastaCorrecao.getInstancia().getDiretorio().getAbsolutePath() + 
               "/" + Constantes.NARQ_COR);
       File arqListaQuestoes = new File(PastaCorrecao.getInstancia().getDiretorio().getAbsolutePath() + 
               "/" + Constantes.NARQ_LIS);
       File arqBancoQuestoes = new File(PastaCorrecao.getInstancia().getDiretorio().getAbsolutePath() + 
               "/" + nArq_Ban);
       FileOutputStream fosCorrecao, fosListaQuestoes, fosBancoQuestoes;
       ObjectOutputStream oosCorrecao, oosListaQuestoes, oosBancoQuestoes;
       
       try {
          fosCorrecao = new FileOutputStream(arqCorrecao);
          oosCorrecao = new ObjectOutputStream(fosCorrecao);
          fosListaQuestoes = new FileOutputStream(arqListaQuestoes);
          oosListaQuestoes = new ObjectOutputStream(fosListaQuestoes);
          fosBancoQuestoes = new FileOutputStream(arqBancoQuestoes);
          oosBancoQuestoes = new ObjectOutputStream(fosBancoQuestoes);
          
          oosCorrecao.writeObject((PastaCorrecao) PastaCorrecao.getInstancia());
          oosCorrecao.close();
          
          oosListaQuestoes.writeObject((ListaQuestoes) ListaQuestoes.getInstancia());
          oosListaQuestoes.close();
          
          oosBancoQuestoes.writeObject((BancoQuestoes) BancoQuestoes.getInstancia());
          oosBancoQuestoes.writeObject((Estado) Estado.getInstancia());
          oosBancoQuestoes.writeObject((int)BancoQuestoes.getEscolha());
          oosBancoQuestoes.writeObject((int)BancoQuestoes.getSimulado());
          oosBancoQuestoes.close();
          
       } catch (IOException e) {
          e.printStackTrace();
       }
    }
    
    public static void serializarQuestao(Questao questao, File arqQuestao){
        FileOutputStream fosQuestao;
        ObjectOutputStream oosQuestao;
        
        try{
            fosQuestao = new FileOutputStream(arqQuestao);
            oosQuestao = new ObjectOutputStream(fosQuestao);
            
            oosQuestao.writeObject(questao);
        } catch(IOException e){
            e.printStackTrace();
        }
    }
    
    public static void serializarQuestaoVisualizacao(Questao questao, File arqQuestao){
        FileOutputStream fosQuestao;
        ObjectOutputStream oosQuestao;
               
        try{
            fosQuestao = new FileOutputStream(arqQuestao);
            oosQuestao = new ObjectOutputStream(fosQuestao);
            
            oosQuestao.writeObject(questao);
        } catch(IOException e){
            e.printStackTrace();
        }
    }
    
    public static void serializarBanco(File arqBanco){
        FileOutputStream fosBancoQuestoes;
        ObjectOutputStream oosBancoQuestoes;
        
        try{
            fosBancoQuestoes = new FileOutputStream(arqBanco);
            oosBancoQuestoes = new ObjectOutputStream(fosBancoQuestoes);

            oosBancoQuestoes.writeObject((BancoQuestoes)BancoQuestoes.getInstancia());
            oosBancoQuestoes.writeObject((Estado)Estado.getInstancia());
            oosBancoQuestoes.writeObject((int)BancoQuestoes.getEscolha());
            oosBancoQuestoes.writeObject((int)BancoQuestoes.getSimulado());
            
            oosBancoQuestoes.close();
            
        } catch(IOException e){
            e.printStackTrace();
        }
    }
    
    public static void serializarBancoVisualizacao(File arqBanco){
        FileOutputStream fosBancoQuestoes;
        ObjectOutputStream oosBancoQuestoes;
        
        int tam = BancoQuestoes.getInstancia().size();
        int tam2 = 0;
        int i = 0;
        int j = 0;
        
        for(i=0; i < tam; i++){
        	tam2 = BancoQuestoes.getInstancia().getQuestaoProva(i).size();
        	for(j=0; j < tam2; j++){
        		BancoQuestoes.getInstancia().getQuestaoProva(i).get(j).setGabarito(null);
        	}
        }
        
        try{
            fosBancoQuestoes = new FileOutputStream(arqBanco);
            oosBancoQuestoes = new ObjectOutputStream(fosBancoQuestoes);

            oosBancoQuestoes.writeObject((BancoQuestoes)BancoQuestoes.getInstancia());
            oosBancoQuestoes.writeObject((Estado)Estado.getInstancia());
            oosBancoQuestoes.writeObject((int)BancoQuestoes.getEscolha());
            oosBancoQuestoes.writeObject((int)BancoQuestoes.getSimulado());
            
            oosBancoQuestoes.close();
            
        } catch(IOException e){
            e.printStackTrace();
        }
    }
    /**
     * Importa os dados armazenados no arquivo para a mem�ria na forma da vari�vel
     * de classe PastaCorrecao.
     * @return A inst�ncia da vari�vel que foi desserializada, ou seja, importada de
     * um arquivo.
     */
    public static PastaCorrecao desserializarCorrecao(File diretorio) throws IOException {
       File arqCorrecao = new File(diretorio.getAbsolutePath() + "/" + Constantes.NARQ_COR);
       InputStream isCorrecao;
       ObjectInputStream oisCorrecao;  
       PastaCorrecao pastaCorrecao = null;
       
       if (arqCorrecao.exists()) {
           try {
              isCorrecao = new FileInputStream(arqCorrecao);
              oisCorrecao = new ObjectInputStream(isCorrecao);
              pastaCorrecao =  (PastaCorrecao) oisCorrecao.readObject();
           } catch (ClassNotFoundException e) {
              e.printStackTrace();
           }
       } else {
           throw new IOException();
       }
       return pastaCorrecao;
    }
    
    public static ListaQuestoes desserializarListaQuestoesDir(File diretorio) throws IOException {
       File arqListaQuestoes = new File(diretorio.getAbsolutePath() + "/" + Constantes.NARQ_LIS);
       InputStream isListaQuestoes;
       ObjectInputStream oisListaQuestoes;
       ListaQuestoes listaQuestoes = null;
       
       if (arqListaQuestoes.exists()) {
           try {
              isListaQuestoes = new FileInputStream(arqListaQuestoes);
              oisListaQuestoes = new ObjectInputStream(isListaQuestoes);
              listaQuestoes =  (ListaQuestoes) oisListaQuestoes.readObject();
           } catch (ClassNotFoundException e) {
              e.printStackTrace();
           }
       } else {
           throw new IOException();
       }
       return listaQuestoes;
    }
    
    public static ListaQuestoes desserializarListaQuestoesArq(File arqListaQuestoes) throws IOException {
       InputStream isListaQuestoes;
       ObjectInputStream oisListaQuestoes;
       ListaQuestoes listaQuestoes = null;
       
       if (arqListaQuestoes.exists()) {
           try {
              isListaQuestoes = new FileInputStream(arqListaQuestoes);
              oisListaQuestoes = new ObjectInputStream(isListaQuestoes);
              listaQuestoes =  (ListaQuestoes) oisListaQuestoes.readObject();
           } catch (ClassNotFoundException e) {
              e.printStackTrace();
           }
       } else {
           throw new IOException();
       }
       return listaQuestoes;
    }
        
     public static BancoQuestoes desserializarBancoQuestoesDir(File diretorio) throws IOException {
       File arqBancoQuestoes = new File(diretorio.getAbsolutePath() + "/" + Constantes.NARQ_BAN);
       InputStream isBancoQuestoes;
       ObjectInputStream oisBancoQuestoes;
       BancoQuestoes bancoQuestoes = null;
       
       if (arqBancoQuestoes.exists()) {
           try {
              isBancoQuestoes = new FileInputStream(arqBancoQuestoes);
              oisBancoQuestoes = new ObjectInputStream(isBancoQuestoes);
              bancoQuestoes =  (BancoQuestoes) oisBancoQuestoes.readObject();
              Estado.setInstancia((Estado) oisBancoQuestoes.readObject());
              bancoQuestoes.setEscolha((Integer)oisBancoQuestoes.readObject());
              bancoQuestoes.setSimulado((Integer)oisBancoQuestoes.readObject());
           } catch (ClassNotFoundException e) {
              e.printStackTrace();
           }
       } else {
           throw new IOException();
       }
       return bancoQuestoes;
     }
     
     public static BancoQuestoes desserializarBancoQuestoesArq(File arqBancoQuestoes) throws IOException {
        InputStream isBancoQuestoes;
        ObjectInputStream oisBancoQuestoes;
        BancoQuestoes bancoQuestoes = null;
        if (arqBancoQuestoes.exists()) {
           try {
              isBancoQuestoes = new FileInputStream(arqBancoQuestoes);
              oisBancoQuestoes = new ObjectInputStream(isBancoQuestoes);
              bancoQuestoes =  (BancoQuestoes) oisBancoQuestoes.readObject();
              Estado.setInstancia((Estado) oisBancoQuestoes.readObject());
              bancoQuestoes.setEscolha((Integer)oisBancoQuestoes.readObject());
              bancoQuestoes.setSimulado((Integer)oisBancoQuestoes.readObject());
              //Estado.setInstancia((Estado) oisBancoQuestoes.readObject());
           } catch (ClassNotFoundException e) {
              e.printStackTrace();
           }
        } else {
           throw new IOException();
        }
        return bancoQuestoes;
     }
     
     public static Questao desserializarQuestao(File arqQuestao) throws IOException {
        InputStream isQuestao;
        ObjectInputStream oisQuestao;
        Questao questao = null;
        
        if(arqQuestao.exists() && arqQuestao.getAbsolutePath().endsWith(".ser")){
            try{
                isQuestao = new FileInputStream(arqQuestao);
                oisQuestao = new ObjectInputStream(isQuestao);
                questao = (Questao) oisQuestao.readObject();
            } catch(ClassNotFoundException e) {
                e.printStackTrace();
            }
        } else {
            throw new IOException();
        }
        return questao;
     }
}
      
